package wechat

import (
	"bytes"
	"context"
	"encoding/json"
	"io/ioutil"
	"net/http"
	"strings"
	"time"

	"mall/common/cachex"

	"github.com/friendsofgo/errors"
	"github.com/zeromicro/go-zero/core/stores/redis"
)

func UploadOrderToWeBackend(ctx context.Context, rds *redis.Redis, appId, secret, accessToken string, data map[string]any, withRetry bool) error {
	url := "https://api.weixin.qq.com/wxa/sec/order/upload_shipping_info?access_token=" + accessToken
	jsonData, err := json.Marshal(data)
	if err != nil {
		return err
	}

	req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
	if err != nil {
		return err
	}

	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{Timeout: 10 * time.Second}

	resp, err := client.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil
	}
	//AccessToken已经过期，重新获取并更新
	if resp.StatusCode == 42001 {
		//重试，但还是过期，返回
		if withRetry {
			return errors.New("access_token expired rid: 685d1002-0d6d7b4a-2912ae1f")
		}

		//更新缓存中微信的AccessToken
		key := cachex.WexinAccessToken
		if accessToken, err = rds.GetCtx(ctx, key); err != nil || len(strings.TrimSpace(accessToken)) == 0 {
			accessToken, err = GetWeAccessToken(appId, secret)
			if err != nil {
				return err
			}
			if len(strings.TrimSpace(accessToken)) > 0 {
				err = rds.SetCtx(ctx, key, accessToken)
				if err != nil {
					return err
				}
				//用新的AccessToken重试一次
				UploadOrderToWeBackend(ctx, rds, appId, secret, accessToken, data, true)
			}
		}
	}

	var res map[string]any
	err = json.Unmarshal(body, &res)
	if err != nil {
		return err
	}
	return nil
}

func GetWeAccessToken(appId string, secret string) (string, error) {
	baseURL := "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appId + "&secret=" + secret

	client := &http.Client{Timeout: 10 * time.Second}

	req, err := http.NewRequest("GET", baseURL, nil)
	if err != nil {
		return "", err
	}

	req.Header.Set("Content-Type", "application/json")

	resp, err := client.Do(req)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}

	if resp.StatusCode != 200 {
		return "", errors.New("GetWeAccessToken  resp.StatusCode != 200")
	}

	var res map[string]any
	err = json.Unmarshal(body, &res)
	if err != nil {
		return "", err
	}
	return res["access_token"].(string), nil
}
